/* 
 * File:   GameOfLife.c
 * Author: Nikolas Wolfe
 *
 * Created on April 24, 2009, 4:39 PM
 */

#include <stdio.h>
#include <stdlib.h>
#include "toroidalArray.h"
#include "configGenerator.h"

/* =============================================================================
 * Function Declaration
 */
void swapArrays( struct array* a, struct array* b );
void traverseSection(   struct array* srcArray, 
                        struct array* destArray, 
                        int startIndex, 
                        int stopIndex );
int checkIfAlive( struct array* arr, int x, int y );
int getLiveNeighborCount( struct array* arr, int x, int y );
void printArray( struct array* a ); 
void populateArrayWithWhite( struct array* arr );
struct array* buildGlider();

/*
 * The Game of Life 
 */
int main(int argc, char** argv) 
{
    int start;
    int stop;
    int i;
    int WIDTH;
    int HEIGHT;
    struct array* src;
    struct array* dest;
    
    src = buildGlider();
    //src = buildExploder();
    
    WIDTH = getXMax( src );
    HEIGHT = getYMax( src );
    dest = createToroidalArray( WIDTH, HEIGHT );
    
    // simulate 3 generations
    for( i = 0; i < 1000; ++i )
    {
        start = 0;
        stop = getXMax( src )-1;
        traverseSection( src, dest, start, stop );
        swapArrays( &dest, &src );
        printArray( dest );
        printf("\n");
    }
    return (EXIT_SUCCESS);
}

/* =============================================================================
 * swap the src and destination arrays
 */
void swapArrays( struct array* dest, struct array* src )
{
    struct array temp;
    temp = *dest;
    *dest = *src;
    *src = temp;
}

/* =============================================================================
 * traverse array subsection
 */
void traverseSection(   struct array* srcArray, 
                        struct array* destArray, 
                        int startIndex, 
                        int stopIndex )
{
    int i, j, yMax, currVal, setVal, isAlive, liveNeighborCount;
    
    yMax = getYMax( srcArray );
  
    for( i = startIndex; i <= stopIndex; ++i ) // do for specified ows
    {
        for( j = 0; j < yMax; ++j )
        {
            // determine this cell's liveness, number of live neighbor cells
            isAlive = checkIfAlive( srcArray, i, j );
            liveNeighborCount = getLiveNeighborCount( srcArray, i, j );
            currVal = get( srcArray, i, j );
            
            // die of loneliness
            if((isAlive) && (liveNeighborCount < 2)) 
            {
                // RED = died this generation
                setVal = RED;
            }
            
            // die of overcrowding
            else if((isAlive) && (liveNeighborCount > 3))
            {
                // RED = died this generation
                 setVal = RED;
            }
            
            // cell is alive and green THIS generation
            else if((isAlive) && (currVal == GREEN))
            {
                // BLUE = live for more than 1 generation
                 setVal = BLUE;
            }
            
            // spring to life!
            else if((!isAlive) && (liveNeighborCount == 3))
            {
                // GREEN = born this generation
                 setVal = GREEN;
            }
            
            // cell is dead and RED this generation
            else if((!isAlive) && (currVal == RED))
            {
                setVal = WHITE;
            }
            
            else // stay the same
            {
                setVal = currVal;
            }
            set( destArray, i, j, setVal );
        }
    }
} 

/* =============================================================================
 * determine if cell is alive
 */
int checkIfAlive( struct array* arr, int x, int y )
{
    int val = get( arr, x, y );
    if( val == GREEN || val == BLUE )
    {
        return 1;
    }
    else 
    {
        return 0;
    }
}

/* =============================================================================
 * determine adjacent live cells
 */
int getLiveNeighborCount( struct array* arr, int x, int y )
{
    int liveCount = 0;
    
    // figure out the adjaceny of live cells surrounding this point
    liveCount += checkIfAlive( arr, (x-1), (y) ); // North
    liveCount += checkIfAlive( arr, (x+1), (y) ); // South
    liveCount += checkIfAlive( arr, (x), (y+1) ); // East
    liveCount += checkIfAlive( arr, (x), (y-1) ); // West
		
    liveCount += checkIfAlive( arr, (x-1), (y-1) ); // Northwest
    liveCount += checkIfAlive( arr, (x-1), (y+1) ); // Northeast
    liveCount += checkIfAlive( arr, (x+1), (y-1) ); // Southwest
    liveCount += checkIfAlive( arr, (x+1), (y+1) ); // Southeast
		
    return liveCount;
}

/* =============================================================================
 * print current generation
 */
void printArray( struct array* arr ) 
{
    int i;
    int j;
    int curr;
    char c;
    int xMax = getXMax( arr );
    int yMax = getYMax( arr );
    
    for( i = 0; i < xMax; ++i )
    {
        for( j = 0; j < yMax; ++j )
        {
            curr = get( arr, i, j );
            if( curr == WHITE ) {c = 'W';}
            else if( curr == RED ) {c = 'R';}
            else if( curr == GREEN ) {c = 'G';}
            else if( curr == BLUE ) {c = 'B';}
            else {c = 'W';}
            printf( "%c ", c);
        }
        printf( "\n" );
    }
}

/* =============================================================================
 * initialize the array
 */
void populateArrayWithWhite( struct array* arr )
{
    int i;
    int j;
    int xMax = getXMax( arr );
    int yMax = getYMax( arr );
    
    for( i = 0; i < xMax; ++i )
    {
        for( j = 0; j < yMax; ++j )
        {
            set( arr, i, j, WHITE );
        }
    }   
}

